[AWS CDK] Step FunctionsステートマシンでLambdaInvokeでの”payloadResponseOnly”の指定による動作の違いを確認してみた
こんにちは、CX事業本部 IoT事業部の若槻です。
今回は、AWS CDKでのAWS Step Functionsステートマシンの構築で、LambdaInvokeでのpayloadResponseOnly
の指定による動作の違いを確認してみました。
LambdaInvokeとは
ステートマシンからLambda関数を実行するタスクをAWS CDKで実装したい場合、CallAwsServiceまたはLambdaInvokeのコンストラクトを使用します。
CallAwsServiceは、AWSサービスのAPIを汎用的に叩けるコンストラクトです。
LambdaInvokeは、Lambda関数を実行するためのコンストラクトです。
LambdaInvokeの方が高レベルで使用可能なプロパティが限られていますが、大抵の場合はこちらの使用で対応可能です。
そしてこのコンストラクトにはpayloadResponseOnly
というプロパティがあります。指定はオプションで、既定ではfalse
となります。
payloadResponseOnly?
Type: boolean (optional, default: false)Invoke the Lambda in a way that only returns the payload response without additional metadata.
The payloadResponseOnly property cannot be used if integrationPattern, invocationType, clientContext, or qualifier are specified. It always uses the REQUEST_RESPONSE behavior.
今回はこのpayloadResponseOnly
のtrue
/false
の指定による動作の違いを確認してみます。
確認してみた
payloadResponseOnly:falseの場合
まずpayloadResponseOnlyがfalse
の場合の動作についてです。
次の通りCDKスタックを作成しました。LambdaInvoke
コンストラクトでpayloadResponseOnly
プロパティでfalse
を指定しています。
import * as cdk from '@aws-cdk/core'; import * as lambdaNodejs from '@aws-cdk/aws-lambda-nodejs'; import * as sfn from '@aws-cdk/aws-stepfunctions'; import * as tasks from '@aws-cdk/aws-stepfunctions-tasks'; export class AwsCdkAppStack extends cdk.Stack { constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const convertValueFormatFunc = new lambdaNodejs.NodejsFunction( this, 'convertValueFormatFunc', { functionName: 'convertValueFormatFunc', entry: 'src/lambda/handlers/sampleHandler.ts', } ); const convertValueFormatTask = new tasks.LambdaInvoke( this, 'convertValueFormatTask', { lambdaFunction: convertValueFormatFunc, payload: sfn.TaskInput.fromJsonPathAt('$'), payloadResponseOnly: false //未指定なら既定でfalseとなる } ); new sfn.StateMachine(this, 'testStateMachine', { stateMachineName: 'testStateMachine', definition: convertValueFormatTask, }); } }
Lambda関数のコードは次の通りです。入力されたnumValueプロパティの値を文字列に変換してstrValueプロパティの値としてReturnしています。
interface Event { numValue: number; } interface Output { strValue: string; } export const handler = async (event: Event): Promise<Output> => { return { strValue: event.numValue.toString(), }; };
cdk deploy
でデプロイしてステートマシンを作成します。
作成されたステートマシンの定義は下記のようになります。
{ "StartAt": "convertValueFormatTask", "States": { "convertValueFormatTask": { "End": true, "Retry": [ { "ErrorEquals": [ "Lambda.ServiceException", "Lambda.AWSLambdaException", "Lambda.SdkClientException" ], "IntervalSeconds": 2, "MaxAttempts": 6, "BackoffRate": 2 } ], "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke", "Parameters": { "FunctionName": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:convertValueFormatFunc", "Payload.$": "$" } } } }
このステートマシンに次の入力を指定して実行します。
{ "numValue": 10 }
実行が成功しました。実行結果の履歴は次の通りです。
convertValueFormatTask
のTaskScheduled
(タスクの入力)は次のようになりました。Lambdaの入力ペイロードに、ステートマシンの入力の値が指定できています。
{ "resourceType": "lambda", "resource": "invoke", "region": "ap-northeast-1", "parameters": { "FunctionName": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:convertValueFormatFunc", "Payload": { "numValue": 10 } }, "timeoutInSeconds": null, "heartbeatInSeconds": null }
またconvertValueFormatTask
のTaskStateExited
(タスクの出力)は次のようになりました。Lambda関数の戻り値のペイロードのパスはoutput.Payload
となっています。また戻り値以外に様々なメタデータが取得できています。
{ "name": "convertValueFormatTask", "output": { "ExecutedVersion": "$LATEST", "Payload": { "strValue": "10" }, "SdkHttpMetadata": { "AllHttpHeaders": { "X-Amz-Executed-Version": [ "$LATEST" ], "x-amzn-Remapped-Content-Length": [ "0" ], "Connection": [ "keep-alive" ], "x-amzn-RequestId": [ "0bb36b3d-f415-46bb-a540-bffa15d86e4d" ], "Content-Length": [ "17" ], "Date": [ "Wed, 15 Dec 2021 14:59:04 GMT" ], "X-Amzn-Trace-Id": [ "root=1-61ba02b8-2e7068885bd4927a41f93ee8;sampled=0" ], "Content-Type": [ "application/json" ] }, "HttpHeaders": { "Connection": "keep-alive", "Content-Length": "17", "Content-Type": "application/json", "Date": "Wed, 15 Dec 2021 14:59:04 GMT", "X-Amz-Executed-Version": "$LATEST", "x-amzn-Remapped-Content-Length": "0", "x-amzn-RequestId": "0bb36b3d-f415-46bb-a540-bffa15d86e4d", "X-Amzn-Trace-Id": "root=1-61ba02b8-2e7068885bd4927a41f93ee8;sampled=0" }, "HttpStatusCode": 200 }, "SdkResponseMetadata": { "RequestId": "0bb36b3d-f415-46bb-a540-bffa15d86e4d" }, "StatusCode": 200 }, "outputDetails": { "truncated": false } }
payloadResponseOnly:trueの場合
次にpayloadResponseOnlyがtrue
の場合の動作についてです。
LambdaInvokeコンストラクトでpayloadResponseOnlyプロパティを
true`に修正します。
const convertValueFormatTask = new tasks.LambdaInvoke( this, 'convertValueFormatTask', { lambdaFunction: convertValueFormatFunc, payload: sfn.TaskInput.fromJsonPathAt('$'), payloadResponseOnly: true } );
Lambda関数は修正しないでおきます。cdk deploy
でタスクの変更をデプロイします。
作成されたステートマシンの定義は下記のようになります。payloadResponseOnly:false
の場合とdiffで比較すると、Resource
とParameters
の指定が異なっています。
{ "StartAt": "convertValueFormatTask", "States": { "convertValueFormatTask": { "End": true, "Retry": [ { "ErrorEquals": [ "Lambda.ServiceException", "Lambda.AWSLambdaException", "Lambda.SdkClientException" ], "IntervalSeconds": 2, "MaxAttempts": 6, "BackoffRate": 2 } ], "Type": "Task", + "Resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:convertValueFormatFunc", + "Parameters": "$" - "Resource": "arn:aws:states:::lambda:invoke", - "Parameters": { - "FunctionName": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:convertValueFormatFunc", - "Payload.$": "$" - } } } }
このステートマシンに先程と同じく次の入力を指定して実行します。
{ "numValue": 10 }
実行が失敗しました。実行結果の履歴は次の通りです。
convertValueFormatTask
のTaskScheduled
(タスクの入力)は次のようになりました。Lambdaの入力ペイロードで$
が解決できておらず、ステートマシンの入力の値が指定できていません。
{ "resource": "arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:convertValueFormatFunc", "input": "$", "inputDetails": { "truncated": false }, "timeoutInSeconds": null }
またconvertValueFormatTask
のTaskStateExited
(タスクの出力)は次のようになりました。案の定Lambda関数の実行がエラーとなっています。
{ "error": "TypeError", "cause": { "errorType": "TypeError", "errorMessage": "Cannot read property 'toString' of undefined", "trace": [ "TypeError: Cannot read property 'toString' of undefined", " at Runtime.handler (/var/task/index.js:15:30)", " at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)" ] } }
payloadResponseOnly:true
の場合はLambdaの入力ペイロードを指定できないようです。
そこでLambda関数で入力は使用せず、出力の値を取得するのみの構成としてみます。
まずLambdaInvokeコンストラクトでpayload
プロパティを削除します。
const convertValueFormatTask = new tasks.LambdaInvoke( this, 'convertValueFormatTask', { lambdaFunction: convertValueFormatFunc, payloadResponseOnly: true, } );
そしてLambda関数のコードを入力を使用しない記述とします。
interface Output { strValue: string; } export const handler = async (): Promise<Output> => { return { strValue: '10', }; };
変更をデプロイしてステートマシンを実行します。
実行が成功しました。実行結果の履歴は次の通りです。
convertValueFormatTask
のTaskStateExited
(タスクの出力)は次のようになりました。Lambda関数の戻り値のペイロードのパスはoutput
となっています。またメタデータなどのペイロード以外のデータは出力されていません。
{ "name": "convertValueFormatTask", "output": { "strValue": "10" }, "outputDetails": { "truncated": false } }
まとめ
LambdaInvokeコンストラクトでのpayloadResponseOnly
の指定の違いをまとめると次のようになりました。
false |
true |
|
---|---|---|
入力ペイロードの指定 | 可能 | 不可 |
出力ペイロードのパス | output.Payload |
output |
出力メタデータ | あり | なし |
Lambda関数で入力ペイロードに応じた処理を行いたい場合はpayloadResponseOnly
をtrue
、そうでない場合はfalse
と指定すれば良さそうですね。
参考
以上